home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1994 April / Inside Multimedia CD-ROM (April 1994).iso / prg / gs / gssource.exe / SCFE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  8.8 KB  |  306 lines

  1. /* Copyright (C) 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* scfe.c */
  21. /* CCITTFax encoding filter */
  22. #include <stdio.h>
  23. #include "memory_.h"
  24. #include "std.h"
  25. #include "gdebug.h"
  26. #include "scf.h"
  27. #include "stream.h"
  28.  
  29. /* Imported procedures */
  30. extern int s_filter_write_flush(P1(stream *));
  31.  
  32. /* ------ Macros and support routines ------ */
  33.  
  34. /* Put a code onto the target stream. */
  35. /* Relevant invariants: 0 <= bits_left <= bits_size; only the leftmost */
  36. /* (bits_size - bits_left) bits of bits contain valid data. */
  37.  
  38. #define bits_size (arch_sizeof_int == 2 ? 16 : 32)
  39.  
  40. #ifdef DEBUG
  41. #  define p_c(rp)\
  42.     (gs_debug['w'] ?\
  43.      (dprintf2("[w]0x%x,%d\n", (rp)->code, (rp)->code_length), 0) : 0)
  44. #else
  45. #  define p_c(rp) 0
  46. #endif
  47.  
  48. #define cf_put_code(s, rp)\
  49.   (p_c(rp),\
  50.    ((s->cfs.bits_left -= (rp)->code_length) >= 0 ?\
  51.     s->cfs.bits += (rp)->code << s->cfs.bits_left :\
  52.     cf_put_code_out(s, (rp)->code)))
  53.  
  54. private uint
  55. cf_put_code_out(register stream *s, uint code)
  56. {    int left = s->cfs.bits_left;
  57.     const uint cw = s->cfs.bits + (code >> -left);
  58.     stream *strm = s->strm;
  59. #if bits_size > 16
  60.     sputc(strm, cw >> 24);
  61.     sputc(strm, (byte)(cw >> 16));
  62. #endif
  63.     sputc(strm, (byte)(cw >> 8));
  64.     sputc(strm, (byte)cw);
  65.     return (s->cfs.bits = code << (s->cfs.bits_left = left + bits_size));
  66. }
  67.  
  68. /* Put a run onto the output stream. */
  69.  
  70. #define cf_put_run(s, lenv, tt, mut)\
  71. {    const cfe_run _ds *rp;\
  72.     if ( lenv >= 64 )\
  73.     {    rp = &mut[lenv >> 6];\
  74.         cf_put_code(s, rp);\
  75.         lenv &= 63;\
  76.     }\
  77.     rp = &tt[lenv];\
  78.     cf_put_code(s, rp);\
  79. }
  80.  
  81. #define cf_put_white_run(s, lenv)\
  82.   cf_put_run(s, lenv, cf_white_termination, cf_white_make_up)
  83.  
  84. #define cf_put_black_run(s, lenv)\
  85.   cf_put_run(s, lenv, cf_black_termination, cf_black_make_up)
  86.  
  87. /* ------ Stream procedures ------ */
  88.       
  89. /*
  90.  * For the 2-D encoding modes, we leave the previous complete scan line
  91.  * at the beginning of the buffer, and start the new data after it.
  92.  */
  93.  
  94. /* Initialize CCITTFaxEncode filter */
  95. void
  96. s_CFE_init(register stream *s, CCITTFax_state *pcfs)
  97. {    s->cfs = *pcfs;
  98.     if ( s->cfs.K != 0 )
  99.     {    /* Clear the initial reference line for 2-D encoding. */
  100.         s->cptr = s->cbuf + s->cfs.raster - 1;
  101.         memset(s->cbuf, (s->cfs.BlackIs1 ? 0xff : 0), s->cfs.raster);
  102.         s->cfs.k_left = -1;
  103.     }
  104.     s->cfs.k_left = max(s->cfs.K, 0);
  105.     s->cfs.bits = 0;
  106.     s->cfs.bits_left = bits_size;
  107. }
  108.  
  109. /* Flush the buffer */
  110. private int cf_encode_1d(P2(stream *, byte *));
  111. private int cf_encode_2d(P3(stream *, byte *, byte *));
  112. private int
  113. s_CFE_write_buf(register stream *s)
  114. {    int raster = s->cfs.raster;
  115.     byte *prev = s->cbuf;
  116.     byte *p = (s->cfs.K ? prev + raster : prev);
  117.     byte *limit = s->cptr;
  118.     byte end_mask = 1 << (-s->cfs.Columns & 7);
  119.     uint count;
  120.     /* Do complete scan lines. */
  121.     while ( (count = limit - p + 1) >= raster )
  122.     {    /* Ensure that the scan line ends with a polarity change. */
  123.         /* This may involve saving and restoring one byte beyond */
  124.         /* the scan line. */
  125.         byte *next = p + raster;
  126.         byte save_next = *next;
  127.         int code;
  128.         if ( end_mask == 1 )        /* set following byte */
  129.             *next = (next[-1] & 1) - 1;
  130.         else if ( next[-1] & end_mask )    /* clear lower bits */
  131.             next[-1] &= -end_mask;
  132.         else                /* set lower bits */
  133.             next[-1] |= end_mask - 1;
  134.         if ( s->cfs.EncodedByteAlign )
  135.             s->cfs.bits_left &= ~7;
  136.         if ( s->cfs.K > 0 )
  137.         {    /* Group 3, mixed encoding */
  138.             if ( --(s->cfs.k_left) )
  139.             {    /* Use 2-D encoding */
  140.                 if ( s->cfs.EndOfLine )
  141.                     cf_put_code(s, &cf2_run_eol_2d);
  142.                 code = cf_encode_2d(s, p, prev);
  143.             }
  144.             else
  145.             {    /* Use 1-D encoding */
  146.                 if ( s->cfs.EndOfLine )
  147.                     cf_put_code(s, &cf2_run_eol_1d);
  148.                 code = cf_encode_1d(s, p);
  149.                 s->cfs.k_left = s->cfs.K;
  150.             }
  151.         }
  152.         else
  153.         {    /* Uniform encoding */
  154.             if ( s->cfs.EndOfLine )
  155.                 cf_put_code(s, &cf_run_eol);
  156.             code = (s->cfs.K == 0 ? cf_encode_1d(s, p) :
  157.                 cf_encode_2d(s, p, prev));
  158.         }
  159.         *next = save_next;
  160.         if ( code )
  161.         {    s->end_status = code;
  162.             break;
  163.         }
  164.         prev = p;
  165.         p = next;
  166.     }
  167.     /* Move any remaining partial scan line (and, if 2-D encoding */
  168.     /* is a possibility, the last full scan line) to the beginning */
  169.     /* of the buffer. */
  170.     if ( s->cfs.K )
  171.         count += raster, p -= raster;
  172.     memcpy(s->cbuf, p, count);
  173.     s->cptr = s->cbuf - 1 + count;
  174.     return 0;
  175. }
  176.  
  177. /* Encode a 1-D scan line. */
  178. private int
  179. cf_encode_1d(stream *s, register byte *p)
  180. {    byte invert = (s->cfs.BlackIs1 ? 0 : 0xff);
  181.     register uint count;
  182.     uint end_count = s->cfs.Columns & 7;
  183.     register uint data = *p++ ^ invert;
  184.     for ( count = s->cfs.raster << 3; count != end_count; )
  185.     {    int white, black;
  186.         /* Parse a white run. */
  187.         white = count;
  188.         skip_white_pixels(data, p, count, invert, w0);
  189.         white -= count;
  190.         cf_put_white_run(s, white);
  191.         if ( count == end_count ) break;
  192.         /* Parse a black run. */
  193.         black = count;
  194.         skip_black_pixels(data, p, count, invert, b0, b1);
  195.         black -= count;
  196.         cf_put_black_run(s, black);
  197.     }
  198.     return 0;
  199. }
  200.  
  201. /* Encode a 2-D scan line. */
  202. private int
  203. cf_encode_2d(stream *s, byte *p, byte *prev_p)
  204. {    byte invert = (s->cfs.BlackIs1 ? 0 : 0xff);
  205.     byte invert_white = invert;
  206.     register uint count;
  207.     uint end_count = s->cfs.Columns & 7;
  208.     register uint data = *p++ ^ invert;
  209.     int dist = prev_p - p;
  210.     for ( count = s->cfs.raster << 3; count != end_count; )
  211.     {    /* If invert == invert_white, white and black have their */
  212.         /* correct meanings; if invert == ~invert_white, */
  213.         /* black and white are interchanged. */
  214.         uint a0, a1, b1;
  215.         uint prev_count = count;
  216.         byte prev_data;
  217.         int diff;
  218.         static const byte count_bit[8] =
  219.             { 0x80, 1, 2, 4, 8, 0x10, 0x20, 0x40 };
  220.         prev_p = p + dist;
  221.         prev_data = prev_p[-1] ^ invert;
  222.         /* Find the a1 and b1 transitions. */
  223.         a0 = count;
  224.         skip_white_pixels(data, p, count, invert, w00);
  225.         a1 = count;
  226.         if ( (prev_data & count_bit[prev_count & 7]) )
  227.         {    /* Look for changing white first. */
  228.             skip_black_pixels(prev_data, prev_p, prev_count, invert, b01, b11);
  229.         }
  230.         if ( prev_count != end_count )
  231.         {    skip_white_pixels(prev_data, prev_p, prev_count, invert, w01);
  232.         }
  233.         b1 = prev_count;
  234.         /* In all the comparisons below, remember that count */
  235.         /* runs downward, not upward, so the comparisons are */
  236.         /* reversed. */
  237.         if ( b1 >= a1 + 2 )
  238.         {    /* Could be a pass mode.  Find b2. */
  239.             if ( prev_count != end_count )
  240.             {    skip_black_pixels(prev_data, prev_p,
  241.                          prev_count, invert, b02, b12);
  242.             }
  243.             if ( prev_count > a1 )
  244.             {    /* Use pass mode. */
  245.                 cf_put_code(s, &cf2_run_pass);
  246.                 count = prev_count;
  247.                 p = prev_p - dist;
  248.                 data = p[-1] ^ invert;
  249.                 continue;
  250.             }
  251.         }
  252.         /* Check for vertical coding. */
  253.         diff = a1 - b1;        /* i.e., logical b1 - a1 */
  254.         if ( diff <= 3 && diff >= -3 )
  255.         {    /* Use vertical coding. */
  256.             cf_put_code(s, &cf2_run_vertical[diff + 3]);
  257.             invert = ~invert;    /* a1 polarity changes */
  258.             continue;
  259.         }
  260.         /* No luck, use horizontal coding. */
  261.         cf_put_code(s, &cf2_run_horizontal);
  262.         if ( count != end_count )
  263.         {    skip_black_pixels(data, p, count, invert, b03, b13);    /* find a2 */
  264.         }
  265.         a0 -= a1;
  266.         a1 -= count;
  267.         if ( invert == invert_white )
  268.         {    cf_put_white_run(s, a0);
  269.             cf_put_black_run(s, a1);
  270.         }
  271.         else
  272.         {    cf_put_black_run(s, a0);
  273.             cf_put_white_run(s, a1);
  274.         }
  275.     }
  276.     return 0;
  277. }
  278.  
  279. /* Close the stream */
  280. private int
  281. s_CFE_close(register stream *s)
  282. {    int code = s_CFE_write_buf(s);
  283.     if ( code < 0 ) return code;
  284.     if ( s->cfs.EndOfBlock )
  285.     {    int i = (s->cfs.K < 0 ? 2 : 6);
  286.         const cfe_run _ds *rp =
  287.             (s->cfs.K > 0 ? &cf2_run_eol_1d : &cf_run_eol);
  288.         while ( --i >= 0 )
  289.             cf_put_code(s, rp);
  290.     }
  291.     /* Force out the last byte or bytes. */
  292.     while ( s->cfs.bits_left < bits_size )
  293.     {    stream *strm = s->strm;
  294.         sputc(strm, s->cfs.bits >> (bits_size - 8));
  295.         s->cfs.bits <<= 8;
  296.         s->cfs.bits_left += 8;
  297.     }
  298.     return s_std_close(s);
  299. }
  300.  
  301. /* Stream procedures */
  302. const stream_procs s_CFE_procs =
  303.    {    s_std_noavailable, NULL, s_filter_write_flush, s_CFE_close,
  304.     NULL, s_CFE_write_buf
  305.    };
  306.